// voicePlayer.js - 处理语音播报相关功能

const VoicePlayer = {
    // 属性
    data: {
        voiceEnabled: false,      // 是否启用语音
        isVoicePlaying: false,    // 语音是否正在播放
        voicePlayingText: '',     // 正在播放的文本内容
        audioQueue: [],           // 音频队列
        isAudioPlaying: false,    // 音频是否正在播放
        voiceBuffer: "",          // 语音缓冲区，用于累积完整句子
        voiceBufferTimeout: null, // 缓冲区超时定时器
        minVoiceTextLength: 30,   // 最小语音文本长度
        voiceBufferDelay: 800,    // 缓冲区超时时间(毫秒)
        sentenceEndChars: "。！？",  // 中文句子结束字符
        pauseChars: "，；：、",       // 中文暂停字符
        incompleteSentence: "",   // 存储未完成的句子片段
        isPaused: false,          // 语音播放暂停状态
        currentAudio: null,       // 当前播放的音频对象
        currentMessageId: null,   // 当前正在处理的消息ID
        currentPlayingMessageId: null, // 当前正在播放的消息ID
        inCodeBlock : false,
        codeBlockType : null
    },

    // 初始化
    init() {
        // 确保初始状态是关闭的
        this.data.isVoicePlaying = false;
        this.data.voicePlayingText = '';
        this.data.isPaused = false;

        // 可以添加初始化代码
        return this;
    },

    // 设置语音开关
    setVoiceEnabled(enabled) {
        this.data.voiceEnabled = enabled;
        if (!enabled) {
            this.closeVoice();
        }
    },

    // 刷新语音缓冲区 - 将缓冲内容发送到播放队列并清空
    flushVoiceBuffer() {
        if (this.data.voiceBuffer && this.data.voiceBuffer.trim()) {
            console.log("[语音] 强制刷新缓冲区:", this.data.voiceBuffer);
            // 通过processVoiceBuffer处理
            this.processVoiceBuffer();
        }
        
        // 清除定时器
        if (this.data.voiceBufferTimeout) {
            clearTimeout(this.data.voiceBufferTimeout);
            this.data.voiceBufferTimeout = null;
        }
    },

    handleTextChunk (text, messageId = null) {
        if (!this.data.voiceEnabled || !text.trim()) return;
    
        // 处理代码块的情况
        if (this.inCodeBlock) {
            // 检查是否包含代码块结束标记
            const endIndex = text.indexOf('```');
            if (endIndex !== -1) {
                // 代码块结束
                this.inCodeBlock = false;
                this.codeBlockType = null;
                
                // 检查代码块结束后是否还有其他文本
                const remainingText = text.substring(endIndex + 3);
                if (remainingText.trim()) {
                    // 处理剩余文本
                    const cleanText = this.cleanTextForVoice(remainingText);
                    if (cleanText.trim()) {
                        this.playTextAsVoice(cleanText, messageId);
                    }
                }
                return;
            }
            
            // 仍在代码块中，不处理
            return;
        }
        
        // 检查是否有代码块开始标记
        const startIndex = text.indexOf('```');
        if (startIndex !== -1) {
            // 提取代码块开始前的文本
            const textBeforeCode = text.substring(0, startIndex);
            if (textBeforeCode.trim()) {
                const cleanText = this.cleanTextForVoice(textBeforeCode);
                if (cleanText.trim()) {
                    this.playTextAsVoice(cleanText, messageId);
                }
            }
            
            // 设置代码块状态
            this.inCodeBlock = true;
            
            // 尝试获取代码语言类型
            const codeBlockStart = text.substring(startIndex).match(/```(\w*)/);
            this.codeBlockType = codeBlockStart && codeBlockStart[1] ? codeBlockStart[1] : 'generic';
            
            // 播放提示信息
            this.playTextAsVoice(`接下来是代码，已跳过播报。`, messageId);
            
            // 检查同一片段中是否包含代码块结束标记
            const endIndex = text.lastIndexOf('```');
            if (endIndex !== -1 && endIndex !== startIndex) {
                // 代码块在同一片段中开始和结束
                this.inCodeBlock = false;
                this.codeBlockType = null;
                
                // 检查代码块结束后是否还有其他文本
                const remainingText = text.substring(endIndex + 3);
                if (remainingText.trim()) {
                    // 处理剩余文本
                    const cleanText = this.cleanTextForVoice(remainingText);
                    if (cleanText.trim()) {
                        this.playTextAsVoice(cleanText, messageId);
                    }
                }
            }
            
            return;
        }
        
        // 常规文本，正常处理
        const cleanText = this.cleanTextForVoice(text);
        if (cleanText.trim()) {
            this.playTextAsVoice(cleanText, messageId);
        }
    },

    // 播放文本为语音，实现文本积累
    playTextAsVoice(text, messageId = null) {
        if (!this.data.voiceEnabled || !text.trim()) return;
        
        // 清理文本
        const cleanText = this.cleanTextForVoice(text);
        if (!cleanText.trim()) return;
        
        // 存储当前消息ID
        this.data.currentMessageId = messageId || this.data.currentMessageId;
        
        // 触发高亮事件
        if (messageId) {
            this.triggerHighlightEvent(messageId, cleanText);
        }
        
        //console.log("[语音] 收到新文本:", cleanText);
        
        // 合并之前可能未完成的句子片段
        this.data.voiceBuffer += cleanText;
        
        //console.log("[语音] 当前缓冲区:", this.data.voiceBuffer);
        
        // 清除之前的定时器
        if (this.data.voiceBufferTimeout) {
            clearTimeout(this.data.voiceBufferTimeout);
        }
        
        // 句子结束的标点符号
        const sentenceEndRegex = /[。！？\.!?]/;
        
        // 检查是否有完整句子
        const hasCompleteSentence = sentenceEndRegex.test(this.data.voiceBuffer);
        
        // 是否达到处理的长度条件
        const reachedProcessingLength = this.data.voiceBuffer.length >= this.data.minVoiceTextLength;
        
        //console.log(`[语音] 缓冲区分析: 长度=${this.data.voiceBuffer.length}, 有完整句子=${hasCompleteSentence}`);
        
        // 决定是否立即处理文本
        if ((hasCompleteSentence && reachedProcessingLength) || this.data.voiceBuffer.length >= 150) {
            //console.log("[语音] 条件满足，处理缓冲区内容");
            this.processVoiceBuffer();
        } else {
            //console.log("[语音] 设置延迟处理定时器");
            this.data.voiceBufferTimeout = setTimeout(() => {
                //console.log("[语音] 延迟定时器触发，处理缓冲区");
                this.processVoiceBuffer();
            }, this.data.voiceBufferDelay);
        }
    },

    // 触发高亮事件
    triggerHighlightEvent(messageId, text) {
        if (!messageId || !text) return;
        
        // 创建自定义事件
        const event = new CustomEvent('voiceHighlight', {
            detail: {
                messageId,
                text
            }
        });
        
        // 发送事件
        document.dispatchEvent(event);
        
        //console.log("[语音] 触发高亮事件:", { messageId, textLength: text.length });
    },

    // 处理语音缓冲区，确保句子完整性
    processVoiceBuffer() {
        if (!this.data.voiceBuffer.trim()) return;
        
        //console.log("[语音处理] 开始处理缓冲区内容:", this.data.voiceBuffer);
        
        // 句子结束的标点符号
        const endPunctRegex = /[。！？\.!?]/g;
        
        // 查找最后一个句子结束标点的位置
        let lastEndPunctPos = -1;
        let match;
        while ((match = endPunctRegex.exec(this.data.voiceBuffer)) !== null) {
            lastEndPunctPos = match.index;
        }
        
        //console.log("[语音处理] 最后的句子结束位置:", lastEndPunctPos);
        
        // 如果找到了句子结束标点
        if (lastEndPunctPos >= 0) {
            // 从缓冲区中提取完整句子部分
            const completeContent = this.data.voiceBuffer.substring(0, lastEndPunctPos + 1);
            
            // 保存剩余未完成的句子部分
            this.data.incompleteSentence = this.data.voiceBuffer.substring(lastEndPunctPos + 1);
            
            //console.log("[语音处理] 完整部分:", completeContent);
            //console.log("[语音处理] 未完成部分:", this.data.incompleteSentence);
            
            // 清空缓冲区
            this.data.voiceBuffer = "";
            
            // 将完整的句子部分发送到音频队列
            if (completeContent.trim()) {
                this._addToAudioQueue(completeContent, {
                    messageId: this.data.currentMessageId,
                    textRange: {
                        start: 0,
                        end: completeContent.length
                    }
                });
            }
            
            // 如果有未完成的部分，放回缓冲区等待下一次处理
            if (this.data.incompleteSentence.trim()) {
                this.data.voiceBuffer = this.data.incompleteSentence;
            }
        } else {
            // 当前没有句子结束标点，但为了避免缓冲区过长，也可以在特定条件下处理
            if (this.data.voiceBuffer.length > 100) {
                // 如果文本较长但无句子标点，尝试在逗号、分号等次要标点处分割
                const minorPunctRegex = /[，,；;：:]/g;
                let lastMinorPunctPos = -1;
                while ((match = minorPunctRegex.exec(this.data.voiceBuffer)) !== null) {
                    lastMinorPunctPos = match.index;
                }
                
                if (lastMinorPunctPos >= 0) {
                    // 按次要标点分割
                    const partialContent = this.data.voiceBuffer.substring(0, lastMinorPunctPos + 1);
                    this.data.incompleteSentence = this.data.voiceBuffer.substring(lastMinorPunctPos + 1);
                    
                    //console.log("[语音处理] 按次要标点分割 - 部分:", partialContent);
                    //console.log("[语音处理] 按次要标点分割 - 余留:", this.data.incompleteSentence);
                    
                    this.data.voiceBuffer = "";
                    
                    if (partialContent.trim()) {
                        this._addToAudioQueue(partialContent, {
                            messageId: this.data.currentMessageId,
                            textRange: {
                                start: 0,
                                end: partialContent.length
                            }
                        });
                    }
                    
                    if (this.data.incompleteSentence.trim()) {
                        this.data.voiceBuffer = this.data.incompleteSentence;
                    }
                } else {
                    // 如果连次要标点也没有，但长度过长，强制处理
                    this._addToAudioQueue(this.data.voiceBuffer, {
                        messageId: this.data.currentMessageId,
                        textRange: {
                            start: 0,
                            end: this.data.voiceBuffer.length
                        }
                    });
                    this.data.voiceBuffer = "";
                }
            } else {
                // 短文本无标点，等待更多内容或定时器触发
                //console.log("[语音处理] 当前内容无标点且较短，继续等待");
            }
        }
        
        // 重置未完成句子
        this.data.incompleteSentence = "";
    },

    // 清理文本以适合语音播报
    cleanTextForVoice(text) {
        if (!text) return "";
    
        // 检测是否是代码块，如果是则直接返回空字符串
        if (this._isCodeBlock(text)) {
            return "";
        }
    
        // 移除markdown代码块
        let cleanedText = text.replace(/```[\s\S]*?```/g, "代码块已省略。");
        
        // 移除内联代码，但保留内容
        cleanedText = cleanedText.replace(/`([^`]+)`/g, "$1");
        
        // 处理HTML标签
        cleanedText = cleanedText.replace(/<br\s*\/?>/gi, "，"); 
        cleanedText = cleanedText.replace(/<\/p>/gi, "。"); 
        cleanedText = cleanedText.replace(/<\/h[1-6]>/gi, "。");
        cleanedText = cleanedText.replace(/<[^>]*>/g, "");
        
        // 处理markdown链接
        cleanedText = cleanedText.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
        
        // 处理列表符号
        cleanedText = cleanedText.replace(/^\s*[-*+]\s+/gm, "，");
        
        // 处理特殊符号
        cleanedText = cleanedText.replace(/[*_~|]/g, "");
        
        // 确保清理后的文本保持语义连贯性
        // 修复可能因为HTML清理导致的文本不连贯问题
        cleanedText = cleanedText.replace(/([。！？\.!?])\s*([^。！？\.!?\s])/g, "$1 $2");
        cleanedText = cleanedText.replace(/([，；：,;:])\s*([^，；：,;:\s])/g, "$1 $2");
        
        // 修复可能没有标点符号的情况，添加逗号以帮助断句
        cleanedText = cleanedText.replace(/(\w+)\s+(\w+)/g, "$1，$2");
        
        return cleanedText;
    },

    // 检查文本是否为代码块
    _isCodeBlock(text) {
        // 检查是否包含编程语言特有的关键字和模式
        const codePatterns = [
            // Python
            /\bdef\s+\w+\s*\(/i,
            /\bclass\s+\w+\s*(\(|:)/i,
            /\bimport\s+\w+/i,
            /\bfrom\s+\w+\s+import/i,
            
            // Java
            /\bpublic\s+(class|interface|enum)\s+\w+/i,
            /\bprivate\s+\w+\s+\w+/i,
            /\bprotected\s+\w+\s+\w+/i,
            
            // JavaScript
            /\bfunction\s+\w+\s*\(/i,
            /\bconst\s+\w+\s*=/i,
            /\blet\s+\w+\s*=/i,
            /\bvar\s+\w+\s*=/i,
            
            // 通用代码模式
            /\bfor\s*\(\s*\w+/i,
            /\bwhile\s*\(\s*\w+/i,
            /\bif\s*\(\s*\w+/i,
            /\breturn\s+\w+/i,
            /[{};]\s*$/m,  // 行尾的大括号、分号
            
            // 检测连续的缩进行（代码的常见特征）
            /\n\s+\w+.*\n\s+\w+/
        ];
        
        // 如果匹配任一模式，则认为是代码
        return codePatterns.some(pattern => pattern.test(text));
    },

    // 内部方法：添加到音频队列并开始播放
    _addToAudioQueue(text) {
        //console.log("[语音队列] 添加文本:", text);
        
        // 添加到队列
        this.data.audioQueue.push(text);
        
        // 如果没有正在播放，开始播放
        if (!this.data.isAudioPlaying) {
            this.playNextInQueue();
        }
    },

    // 辅助方法：分割长句子
    _splitLongSentence(sentence, maxLength) {
        // 优先在这些标点符号处分割
        const splitPoints = /([，,；;：:、]+)(\s*)/g;
        const chunks = [];
        let currentChunk = "";
        let lastSplitPoint = 0;
        let match;
        
        // 重置正则表达式的lastIndex
        splitPoints.lastIndex = 0;
        
        while ((match = splitPoints.exec(sentence)) !== null) {
            // 当前标点符号前的文本加上标点符号
            const textWithPunct = sentence.substring(lastSplitPoint, match.index + match[0].length);
            
            // 如果添加这部分会超过最大长度
            if ((currentChunk + textWithPunct).length > maxLength) {
                // 如果当前块已经接近为空，直接添加文本（避免无限循环）
                if (currentChunk.length < 10) {
                    currentChunk += textWithPunct;
                    chunks.push(currentChunk);
                    currentChunk = "";
                } else {
                    // 否则添加当前块，并开始新块
                    chunks.push(currentChunk);
                    currentChunk = textWithPunct;
                }
            } else {
                // 否则添加到当前块
                currentChunk += textWithPunct;
            }
            
            lastSplitPoint = match.index + match[0].length;
        }
        
        // 处理剩余部分
        if (lastSplitPoint < sentence.length) {
            const remaining = sentence.substring(lastSplitPoint);
            
            if ((currentChunk + remaining).length > maxLength) {
                if (currentChunk) {
                    chunks.push(currentChunk);
                }
                
                // 对于没有标点的长文本，按照maxLength直接分割
                for (let i = 0; i < remaining.length; i += maxLength) {
                    chunks.push(remaining.substring(i, Math.min(i + maxLength, remaining.length)));
                }
            } else {
                currentChunk += remaining;
                if (currentChunk) {
                    chunks.push(currentChunk);
                }
            }
        } else if (currentChunk) {
            chunks.push(currentChunk);
        }
        
        return chunks;
    },

    // 公开方法：添加到音频队列
    addToAudioQueue(text) {
        this._addToAudioQueue(text);
    },

    // 播放队列中的下一条
    playNextInQueue() {
        if (this.data.audioQueue.length === 0) {
            this.data.isVoicePlaying = false;
            this.data.isAudioPlaying = false;
            this.data.currentAudio = null;
            return;
        }
        
        const text = this.data.audioQueue.shift();
        this.data.isVoicePlaying = true;
        this.data.isAudioPlaying = true;
        this.data.voicePlayingText = text;
        
        //console.log(`[语音播放] 播放文本: "${text}"`);
        
        // 确保文本末尾有适当的标点
        let formattedText = text.trim();
        const lastChar = formattedText.charAt(formattedText.length - 1);
        
        // 如果不以标点结束，添加适当的标点
        if (!"。！？.!?".includes(lastChar)) {
            formattedText += "。";
        }
        
        // 语音合成请求
        fetch('/api/text-to-speech', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ text: formattedText })
        })
        .then(response => {
            if (response.ok) {
                return response.blob();
            }
            throw new Error('语音合成失败');
        })
        .then(blob => {
            const audioUrl = URL.createObjectURL(blob);
            const audio = new Audio(audioUrl);
            
            // 保存当前音频对象的引用
            this.data.currentAudio = audio;
            
            // 如果当前是暂停状态，不自动播放
            if (this.data.isPaused) {
                //console.log("[语音播放] 新音频处于暂停状态");
            }
            
            audio.onended = () => {
                //console.log("[语音播放] 播放完成");
                URL.revokeObjectURL(audioUrl);
                this.data.currentAudio = null;
                
                // 添加适当的停顿，确保语音之间有自然过渡
                setTimeout(() => {
                    this.playNextInQueue();
                }, 300);  // 300ms的停顿
            };
            
            audio.onerror = (e) => {
                //console.error('[语音播放] 错误:', e);
                URL.revokeObjectURL(audioUrl);
                this.data.currentAudio = null;
                this.playNextInQueue();
            };
            
            // 仅在非暂停状态下播放
            if (!this.data.isPaused) {
                audio.play().catch(err => {
                    //console.error('[语音播放] 播放被阻止:', err);
                    this.data.currentAudio = null;
                    this.playNextInQueue();
                });
            }
        })
        .catch(error => {
            //console.error('[语音播放] 请求失败:', error);
            this.data.currentAudio = null;
            this.playNextInQueue();
        });
    },

    // 切换语音播放暂停状态
    toggleVoicePause() {
        this.data.isPaused = !this.data.isPaused;
        
        if (this.data.currentAudio) {
            if (this.data.isPaused) {
                this.data.currentAudio.pause();
                //console.log("[语音播放] 已暂停");
            } else {
                this.data.currentAudio.play().catch(err => {
                    //console.error('[语音播放] 恢复播放失败:', err);
                });
                //console.log("[语音播放] 已恢复");
            }
        }
    },

    // 关闭语音播放
    closeVoice() {
        // 停止当前播放
        if (this.data.currentAudio) {
            this.data.currentAudio.pause();
            this.data.currentAudio = null;
        }
        
        // 清空队列
        this.data.audioQueue = [];
        
        // 重置状态
        this.data.isVoicePlaying = false;
        this.data.isAudioPlaying = false;
        this.data.isPaused = false;
        this.data.voicePlayingText = '';

        // 清除高亮
        this.triggerClearHighlightsEvent();
        
        //console.log("[语音播放] 已关闭");
    },

    // 触发清除高亮事件
    triggerClearHighlightsEvent() {
        const event = new CustomEvent('voiceClearHighlight');
        document.dispatchEvent(event);
        //console.log("[语音] 触发清除高亮事件");
    }
};

// 导出模块
window.VoicePlayer = VoicePlayer;